#include<iostream>
#include<cstdlib>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<sys/select.h>
#include<sys/epoll.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<netdb.h>
#include<unistd.h>
#include<string.h>
using namespace std;
class EmailTcpIp{
private:
	int sockfd;//myself
	sockaddr_in addrC;//server information
	char ip[20];//server Ip
    struct Base64Date6
    {
        unsigned int d4 : 6;
        unsigned int d3 : 6;
        unsigned int d2 : 6;
        unsigned int d1 : 6;
    };
public:
    EmailTcpIp(const char* ps,int port=25)
    {
        hostent* phost=gethostbyname(ps);
		in_addr addrTemp;
        if(phost==NULL)
        {
            fprintf(stderr,"DNS no find");
            throw;
        }
        char* ptemp=phost->h_addr_list[0];
		memcpy(&addrTemp.s_addr,ptemp,phost->h_length);
        memset(ip,0,20);
        memcpy(ip,inet_ntoa(addrTemp),strlen(inet_ntoa(addrTemp)));cout<<ip<<endl;
		sockfd=socket(PF_INET,SOCK_STREAM,0);
		addrC.sin_addr.s_addr=inet_addr(ip);
		addrC.sin_family=AF_INET;
		addrC.sin_port=htons(port);
    }
    ~EmailTcpIp()
    {
		close(this->sockfd);
    }
    char ConvertToBase64(char uc)
    {
        if (uc < 26)
            return 'A' + uc;
        if (uc < 52)
            return 'a' + (uc - 26);
        if (uc < 62)
            return '0' + (uc - 52);
        if (uc == 62)
            return '+';
        return '/';
    }
    void EncodeBase64(char *dbuf, char *buf128, int len)
    {
        struct Base64Date6 *ddd = NULL;
        int i = 0;
        char buf[256] = { 0 };
        char* tmp = NULL;
        char cc = '\0';
        memset(buf, 0, 256);
        strcpy(buf, buf128);
        for (i = 1; i <= len / 3; i++)
        {
            tmp = buf + (i - 1) * 3;
            cc = tmp[2];
            tmp[2] = tmp[0];
            tmp[0] = cc;
            ddd = (struct Base64Date6 *)tmp;
            dbuf[(i - 1) * 4 + 0] = ConvertToBase64((unsigned int)ddd->d1);
            dbuf[(i - 1) * 4 + 1] = ConvertToBase64((unsigned int)ddd->d2);
            dbuf[(i - 1) * 4 + 2] = ConvertToBase64((unsigned int)ddd->d3);
            dbuf[(i - 1) * 4 + 3] = ConvertToBase64((unsigned int)ddd->d4);
        }
        if (len % 3 == 1)
        {
            tmp = buf + (i - 1) * 3;
            cc = tmp[2];
            tmp[2] = tmp[0];
            tmp[0] = cc;
            ddd = (struct Base64Date6 *)tmp;
            dbuf[(i - 1) * 4 + 0] = ConvertToBase64((unsigned int)ddd->d1);
            dbuf[(i - 1) * 4 + 1] = ConvertToBase64((unsigned int)ddd->d2);
            dbuf[(i - 1) * 4 + 2] = '=';
            dbuf[(i - 1) * 4 + 3] = '=';
        }
        if (len % 3 == 2)
        {
            tmp = buf + (i - 1) * 3;
            cc = tmp[2];
            tmp[2] = tmp[0];
            tmp[0] = cc;
            ddd = (struct Base64Date6 *)tmp;
            dbuf[(i - 1) * 4 + 0] = ConvertToBase64((unsigned int)ddd->d1);
            dbuf[(i - 1) * 4 + 1] = ConvertToBase64((unsigned int)ddd->d2);
            dbuf[(i - 1) * 4 + 2] = ConvertToBase64((unsigned int)ddd->d3);
            dbuf[(i - 1) * 4 + 3] = '=';
        }
        return;
    }
    void CreateSend(const char* youName,const char* toName,const char* from,const char* to,const char* subject,const char* body,char* buf)
    {
        sprintf(buf,"From: \"%s\"<%s>\r\n"
                "To: \"%s\"<%s>\r\n"
                "Subject:%s\r\n\r\n"
                "%s\n",youName,from,toName,to,subject,body);
    }
    bool SendMail(const char* sendEmail,const char* passwd,const char *email, const char *body)
    {
        int     sockfd = { 0 };
        char    buf[1500] = { 0 };
        char    rbuf[1500] = { 0 };
        char    login[128] = { 0 };
        char    pass[128] = { 0 };
        struct sockaddr_in their_addr = { 0 };
        memset(&their_addr, 0, sizeof(their_addr));
        their_addr.sin_family = AF_INET;
        their_addr.sin_port = htons(25);    // 一般是25端口不需要改
        hostent* hptr = gethostbyname("smtp.163.com");          // 端口和服务器
        memcpy(&their_addr.sin_addr.s_addr, hptr->h_addr_list[0], hptr->h_length);

        // 连接邮件服务器，如果连接后没有响应，则2 秒后重新连接
        sockfd = OpenSocket((struct sockaddr *)&their_addr);
        memset(rbuf, 0, 1500);
        while (recv(sockfd, rbuf, 1500, 0) == 0)
        {
            cout << "reconnect..." << endl;
            sleep(2);
            sockfd = OpenSocket((struct sockaddr *)&their_addr);
            memset(rbuf, 0, 1500);
        }

        cout << rbuf << endl;

        // EHLO
        memset(buf, 0, 1500);
        sprintf(buf, "EHLO HYL-PC\r\n");
        send(sockfd, buf, strlen(buf), 0);
        memset(rbuf, 0, 1500);
        recv(sockfd, rbuf, 1500, 0);
        cout << "EHLO REceive: " << rbuf << endl;

        // AUTH LOGIN
        memset(buf, 0, 1500);
        sprintf(buf, "AUTH LOGIN\r\n");
        send(sockfd, buf, strlen(buf), 0);
        memset(rbuf, 0, 1500);
        recv(sockfd, rbuf, 1500, 0);
        cout << "Auth Login Receive: " << rbuf << endl;

        // USER
        memset(buf, 0, 1500);
        sprintf(buf, "%s",sendEmail);//你的邮箱账号
        memset(login, 0, 128);
        EncodeBase64(login, buf, strlen(buf));
        sprintf(buf, "%s\r\n", login);
        send(sockfd, buf, strlen(buf), 0);
        cout << "Base64 UserName: " << buf << endl;
        memset(rbuf, 0, 1500);
        recv(sockfd, rbuf, 1500, 0);
        cout << "User Login Receive: " << rbuf << endl;

        // PASSWORD
        sprintf(buf, "%s",passwd);//你的邮箱密码
        memset(pass, 0, 128);
        EncodeBase64(pass, buf, strlen(buf));
        sprintf(buf, "%s\r\n", pass);
        send(sockfd, buf, strlen(buf), 0);
        cout << "Base64 Password: " << buf << endl;

        memset(rbuf, 0, 1500);
        recv(sockfd, rbuf, 1500, 0);
        cout << "Send Password Receive: " << rbuf << endl;

        // MAIL FROM
        memset(buf, 0, 1500);
        sprintf(buf, "MAIL FROM: <%s>\r\n",sendEmail);  //此处要和发邮件的邮箱保持一致
        send(sockfd, buf, strlen(buf), 0);
        memset(rbuf, 0, 1500);
        recv(sockfd, rbuf, 1500, 0);
        cout << "set Mail From Receive: " << rbuf << endl;

        // RCPT TO 第一个收件人
        sprintf(buf, "RCPT TO:<%s>\r\n", email);
        send(sockfd, buf, strlen(buf), 0);
        memset(rbuf, 0, 1500);
        recv(sockfd, rbuf, 1500, 0);
        cout << "Tell Sendto Receive: " << rbuf << endl;
        int bug=0;
        sscanf(rbuf,"%d",&bug);
        if(bug==550)
            return false;
        // DATA 准备开始发送邮件内容
        sprintf(buf, "DATA\r\n");
        send(sockfd, buf, strlen(buf), 0);
        memset(rbuf, 0, 1500);
        recv(sockfd, rbuf, 1500, 0);
        cout << "Send Mail Prepare Receive: " << rbuf << endl;

        // 发送邮件内容，\r\n.\r\n内容结束标记
        sprintf(buf, "%s\r\n.\r\n", body);
        send(sockfd, buf, strlen(buf), 0);
        memset(rbuf, 0, 1500);
        recv(sockfd, rbuf, 1500, 0);
        cout << "Send Mail Receive: " << rbuf << endl;

        // QUIT
        sprintf(buf,"QUIT\r\n");
        send(sockfd, buf, strlen(buf), 0);
        memset(rbuf, 0, 1500);
        recv(sockfd, rbuf, 1500, 0);
        cout << "Quit Receive: " << rbuf << endl;
        return true;
    }
    // 打开TCP Socket连接
    int OpenSocket(struct sockaddr *addr)
    {
        int sockfd = 0;
        sockfd = socket(PF_INET, SOCK_STREAM, 0);
        if (sockfd < 0)
        {
            cout << "Open sockfd(TCP) error!" << endl;
            exit(-1);
        }
        if (connect(sockfd, addr, sizeof(struct sockaddr)) < 0)
        {
            cout << "Connect sockfd(TCP) error!" << endl;
            exit(-1);
        }
        return sockfd;
    }
};
void sendByMyself(EmailTcpIp& email)
{
    char senName[20]={0};
    char recName[20]={0};
    char recEmail[20]={0};
    char subject[20]={0};
    char say[1000]={0};
    char buf[1000]={0};
    cout<<"please input name of you:";
    cin>>senName;
    cout<<"please input name of rec:";
    cin>>recName;
    cout<<"please input email of rec:";
    cin>>recEmail;
    cout<<"please input subject of email:";
    cin>>subject;
    FILE* fp=fopen("say.txt","r+");
    if(fp==NULL)
        if((fp=fopen("say.txt","w+"))==NULL)
        {
            cerr<<" no init ";
            system("pause");
            return ;
        }
    fseek(fp,0,SEEK_END);
    int len=ftell(fp),i=0;
    if(len<=2)
    {
        cerr<<" no init"<<endl;
        system("pause");
        return ;
    }
    fseek(fp,0,SEEK_SET);
    while(!feof(fp))
        say[i++]=fgetc(fp);
    say[i]=0;
    fclose(fp);
    string sendTo=say;
    sendTo+="\r\n\r\n";
    email.CreateSend(senName,recName,"zyx13145202@163.com",recEmail,subject,sendTo.c_str(),buf);
    if(false==email.SendMail("zyx13145202@163.com","OIECQVOQZFPYZAQO",recEmail,buf))
    {
        cerr<<"email is wrong"<<endl;
        system("pause");
        return ;
    }
    cout<<"send success"<<endl;
    system("pause");
    return ;
}
int main(int argc,char** argv)
{
    char buf[1000]={0};
    char say[100]={0};
    EmailTcpIp email("smtp.163.com");
    if(argc==1)
    {
        sendByMyself(email);
        return 0;
    }
    if(argc==3)
    {
        sprintf(say,"您的验证码为%s",argv[2]);
        const char EmailTo[]="1607772321@qq.com";
        email.CreateSend("www.chenxuan520.xyz",
                        "You",
                        "zyx13145202@163.com",
                        argv[1],
                        "验证码",
                        say,buf);
        if(false==email.SendMail("zyx13145202@163.com","OIECQVOQZFPYZAQO",argv[1],buf))
        {
            cerr<<"email wrong"<<endl;
            return -1;
        }
    }
    
    return 0;
}
